Skip to content

Claimify-loss ledger: no kept span dies silently (#161) - #166

Merged
fazpu merged 4 commits into
mainfrom
fix/claimify-loss-ledger
Jul 28, 2026
Merged

Claimify-loss ledger: no kept span dies silently (#161)#166
fazpu merged 4 commits into
mainfrom
fix/claimify-loss-ledger

Conversation

@fazpu

@fazpu fazpu commented Jul 28, 2026

Copy link
Copy Markdown
Member

Claimify-loss ledger: no kept span dies silently (#161)

Closes #161.

Why

On the glm-4.7-flash arm, 207 of 264 kept candidates (78%) produced no claim
and the ledger said nothing about why
— Claimify omissions were unrecorded
and the three grounding gates in _grounded_claim were silent return Nones.
Cross-model extraction comparisons could say that a stronger model lands
more claims, never why.

What

  • Two new decision types on the D33 transcript: claimify_omitted (a
    kept span the model returned no claim for — including Selection spans not
    verbatim-findable in the document, which previously vanished traceless)
    and grounding_rejected (a returned claim a D32 gate rejected, with the
    gate named in edit_detail: span_not_found / outside_kept_ranges /
    added_context_unverified, plus the truncated offending text).
  • _grounded_claim reports which gate fired instead of bare None; the
    accept path is behaviorally identical.
  • Accounting invariant (in the D33 design amendment): every returned
    claim independently ends accepted or rejected; every keep with no
    range-attributable returned claim gets exactly one omission row; orphan
    rejections suppress no omission.
  • D56 zero-claim reuse carries the prior transcript forward
    (copy_reused_decisions) instead of fabricating a no_info marker over a
    real loss record; the marker is written only when the prior transcript is
    itself empty.
  • Forward-only enum migration (ADD VALUE IF NOT EXISTS, additive, no new
    indexes on the partitioned table); E2_EXTRACTOR_VERSION
    e2-extract-2026.07e:loss-ledger-1 (the transcript a replay writes
    changed shape).

Review trail

Grok-4.5 implemented the base; Codex (gpt-5.6-sol, xhigh) reviewed with
REQUEST-CHANGES (3 MAJOR / 3 MINOR); this revision applies all findings:

  1. Attribution could suppress omission rows — fixed with range-overlap-only
    attribution
    (text-containment shortcuts removed). Deliberate deviation
    from the suggested fix (numbering keeps in the Claimify prompt): that
    changes the model-facing contract and adds a schema field weak models can
    get wrong (§2.4), while range-only attribution closes the same hole
    code-side. Orphan rejections and unfindable keeps now behave conservatively
    and documented.
  2. Zero-claim reuse rewrote losses as no_info — fixed via transcript
    copy-forward with marker fallback, plus a Postgres-gated test.
  3. Tests didn't exercise the handler — five handler-level scenarios now
    drive the real _extract_chunk with canned Selection/Claimify payloads
    (zero-return, rejection-only, mixed accept+reject, orphan rejection,
    unfindable keep); break→fail→restore verified on the attribution rule.
  4. "Exactly one category" invariant wrong for mixed outcomes — restated as
    two independent rules in the design amendment.
  5. Unbounded model-controlled ledger fieldskind and the row's
    source_span now truncate like the rest.
  6. Stale binding text — D33 (decisions.md) amended; postgres schema design
    updated (enum values, "discarded" → ledgered, loss-row sizing note).

Gate

ruff format/check clean, pyright 0 errors, full pytest incl. Postgres-gated
suites — see checks.

fazpu and others added 3 commits July 27, 2026 16:27
Every kept Selection span is now accounted for end-to-end: grounding gates
emit grounding_rejected with the gate name, and Claimify skips emit
claimify_omitted (without double-counting rejected attempts). Bumps the E2
extractor version so the changed decision transcript is a new provenance
generation.
…, handler tests

Codex review (REQUEST-CHANGES, 3 MAJOR / 3 MINOR) applied:

- claimify_omitted attribution is anchored-range overlap ONLY — the
  text-containment shortcuts let one returned claim suppress omission rows
  for unrelated keeps sharing text. Orphan rejections (span anchors nowhere
  or outside every kept range) suppress no omission; unfindable Selection
  keeps always get their omission row. Deliberate deviation from the
  review's keep-numbering suggestion: that changes the model-facing Claimify
  contract (weak-model schema risk, section 2.4); range-only closes the
  hole code-side.
- D56 zero-claim reuse copies the prior chunk's decision transcript forward
  (new ClaimCatalog.copy_reused_decisions) instead of fabricating a
  no_info marker over real loss rows; marker only when the prior transcript
  is empty.
- Five handler-level tests drive the real _extract_chunk with canned
  payloads (zero-return, rejection-only, mixed accept+reject, orphan
  rejection, unfindable keep); attribution rule break/fail/restore
  verified. Postgres-gated copy_reused_decisions test added.
- Invariant restated as two independent rules (mixed decomposition
  outcomes); kind and row source_span bounded; D33 (decisions.md) and the
  postgres schema design amended (enum values, discarded -> ledgered).

Gate: ruff clean, pyright 0 errors, pytest 948 passed incl. Postgres-gated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The Compose quickstart workflow hardcodes the post-migration alembic head;
the loss-ledger migration moved it. Same pin the migration-graph test
already carries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  src/rememberstack/model
  claims.py
  src/rememberstack/spine
  claim_catalog.py
  src/rememberstack/spine/migrations/versions
  p1_03_0018_claimify_loss_ledger.py
  src/rememberstack/workers
  e1.py
  e2.py 198-202, 639, 658
Project Total  

This report was generated by python-coverage-comment-action

@fazpu
fazpu merged commit a367017 into main Jul 28, 2026
6 checks passed
@fazpu
fazpu deleted the fix/claimify-loss-ledger branch July 28, 2026 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Claimify-stage losses are silent: 78% of kept candidates never became claims and no ledger row says why

1 participant